﻿/* 多线程工作类
 */

/*待测试*/
namespace LSLib.Threading
{
    using System;
    using System.Collections.Generic;
    using System.Threading;

    public struct WorkInfo
    {
        public Delegate Call;
        public object[] Args;
    }

    public class MultiWorker
    {
        private int m_MaxThreads;
        private int m_ThreadCount;
        private Queue<WorkInfo> m_Works;

        public MultiWorker(int maxThreads)
        {
            this.m_MaxThreads = maxThreads;
        }

        public IList<object> Work(params WorkInfo[] works)
        {
            if (works == null || works.Length < 1) return null;

            this.m_Works = new Queue<WorkInfo>();
            foreach (WorkInfo work in works)
            {
                this.m_Works.Enqueue(work);
            }

            this.m_ThreadCount = (this.m_MaxThreads > works.Length) ? works.Length : this.m_MaxThreads;

            AutoResetEvent[] waits = new AutoResetEvent[this.m_ThreadCount];
            for (int i = 0; i < this.m_ThreadCount; i++)
            {
                waits[i] = new AutoResetEvent(false);
            }

            List<object> result = new List<object>();
            for (int i = 0; i < this.m_ThreadCount; i++)
            {
                Thread thread = new Thread(this.WorkThread);
                thread.Start(new object[] { waits[i], result });
            }

            for (int i = 0; i < this.m_ThreadCount; i++)
            {
                waits[i].WaitOne();
            }

            return result.AsReadOnly();
        }

        private void WorkThread(object argsObj)
        {
            object[] args = argsObj as object[];
            AutoResetEvent wait = args[0] as AutoResetEvent;
            List<object> result = args[1] as List<object>;
            while (true)
            {
                WorkInfo work = new WorkInfo();
                lock (this)
                {
                    if (this.m_Works.Count < 1) break;
                    work = this.m_Works.Dequeue();
                }

                object oneResult = work.Call.DynamicInvoke(work.Args);

                lock (this)
                {
                    result.Add(oneResult);
                }
            }
            wait.Set();
        }
    }
}